/**
 * JFunny - A funny programming language
 * Copyright (C) 2013  fanguangping
 * Any problem email me: fguangping@gmail.com
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 3
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 **/
package org.jfunny.core.sys;

import java.io.PushbackReader;
import java.io.StringReader;
import java.util.List;

import org.armedbear.lisp.Interpreter;
import org.jfunny.core.JFunny;
import org.jfunny.core.dfa.DFA;
import org.jfunny.core.ds.Statement;
import org.jfunny.core.ds.StatementMapping;
import org.jfunny.core.parser.ParserFunny;
import org.jfunny.core.parser.ParserTpl;
import org.jfunny.core.parser.ScannerFunny;
import org.jfunny.core.util.FileUtil;
import org.jfunny.core.util.StringUtil;

/**
 * 项目级编译的支持类
 * 
 * @author fanguangping
 *
 */
public class ProjectEvaluator {
	public static final String SYS_TEMPLATE = "lang/sys.tpl";

	public static final String SYS_TRANSLATE = "sys-translate";
	public static final String SYS_MERGE = "sys-merge";
	public static final String SYS_LOAD = "sys-load";

	public static void eval(String prjPath, String prj) throws Exception {
		Interpreter interpreter = Interpreter.getInstance();
		if (interpreter == null) {
			interpreter = Interpreter.createInstance();
		}

		String code = parse(prj);
		String[] lines = code.split("\n");
		for (String line : lines) {
			String name = getFunctionName(line);
			String[] args = getFunctionArgs(line);

			if (SYS_TRANSLATE.equalsIgnoreCase(name)) {
				//String sourcePath = args[0];
				String sourcePath = getPath(prjPath, args[0]);
				//String destPath = args[1];
				String destPath = getPath(prjPath, args[1]);

				//先自定义模板，后系统模板
				StringBuffer buffer = new StringBuffer();
				for (int i = 2; i < args.length; i++) {
					//String tplPath = args[i];
					String tplPath = getPath(prjPath, args[i]);
					String tpl = FileUtil.readTxt(tplPath);
					buffer.append(tpl);
				}
				for (String filePath : JFunny.LANG_TEMPLATES) {
					String tpl = FileUtil.readTxt(filePath);
					buffer.append(tpl);
				}

				String funny = FileUtil.readTxt(sourcePath);

				ParserFunny parser = new ParserFunny(new ScannerFunny(new PushbackReader(new StringReader(funny))));
				List<StatementMapping> statements = new ParserTpl(buffer.toString()).parseTemplate();

				buffer = new StringBuffer();
				while (parser.hasNext()) {
					Statement s = parser.next();

					String result = DFA.getInstance().match(s, statements);

					buffer.append(result);
					buffer.append("\n");
				}

				FileUtil.writeTxt(destPath, buffer.toString());
			}
			else if (SYS_MERGE.equalsIgnoreCase(name)) {
				//String destPath = args[0];
				String destPath = getPath(prjPath, args[0]);
				StringBuffer buffer = new StringBuffer();
				for (int i = 1; i < args.length; i++) {
					//String sourcePath = args[i];
					String sourcePath = getPath(prjPath, args[i]);
					String script = FileUtil.readTxt(sourcePath);
					buffer.append(script);
				}
				FileUtil.writeTxt(destPath, buffer.toString());
			}
			else if (SYS_LOAD.equalsIgnoreCase(name)) {
				String sourcePath = getPath(prjPath, args[0]);
				String loadScript = "( load \"" + sourcePath + "\")";
				interpreter.eval(loadScript);
			}
		}
	}

	private static String getFunctionName(String line) {
		String funcName = StringUtil.substringAfter(line, "(");
		funcName = funcName.trim();
		funcName = StringUtil.substringBefore(funcName, " ");
		return funcName;
	}

	private static String[] getFunctionArgs(String line) {
		String funcArg = StringUtil.substringAfter(line, "(");
		funcArg = funcArg.trim();
		funcArg = StringUtil.substringBefore(funcArg, ")");
		funcArg = funcArg.trim();
		funcArg = StringUtil.substringAfter(funcArg, " ");
		return StringUtil.split(funcArg);
	}

	private static String parse(String funny) throws Exception {
		String tpl = FileUtil.readTxt(SYS_TEMPLATE);

		ParserFunny parser = new ParserFunny(new ScannerFunny(new PushbackReader(new StringReader(funny))));
		List<StatementMapping> statements = new ParserTpl(tpl).parseTemplate();

		StringBuffer buffer = new StringBuffer();
		while (parser.hasNext()) {
			Statement s = parser.next();

			String result = DFA.getInstance().match(s, statements);

			buffer.append(result);
			buffer.append("\n");
		}
		System.out.println(buffer.toString());
		return buffer.toString();
	}

	/**
	 * 根据项目路径和相对子路径生成全路径
	 * @param projectPath
	 * @param childPath
	 * @return
	 */
	private static String getPath(String projectPath, String childPath) {
		projectPath = projectPath.replace("\\", "/");
		childPath = childPath.replace("\\", "/");

		String prefix = null;
		if (projectPath.contains("/")) {
			prefix = StringUtil.substringBeforeLast(projectPath, "/") + "/";
		}
		else {
			prefix = "";
		}

		return prefix + childPath;
	}
}
